﻿/**
 * @file std_comm.c
 * Copyright (c) 2019 Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2019-09-09
 * @version : 1.0.0.0
 * @brief   : common data types and API.
 */

/**
 * The MIT License (MIT)
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "std_comm.h"
#include "std_debug.h"

#include <stdlib.h>
#include <string.h>

#ifndef XSTD_MDBCOMM_ENABLE
#define XSTD_MDBCOMM_ENABLE XSTD_DEBUG_ENABLE
#endif // XSTD_MDBCOMM_ENABLE

#if XSTD_MDBCOMM_ENABLE
#include "std_mdebug.h"
#endif // XSTD_MDBCOMM_ENABLE

////////////////////////////////////////////////////////////////////////////////

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif // __GNUC__

////////////////////////////////////////////////////////////////////////////////

#if XSTD_MDBCOMM_ENABLE
/** 辅助 xstd_altor_comm 记录内存分配信息 */
xmdb_this_t xmdb_altor_comm = XSTD_NULL;
#endif // XSTD_MDBCOMM_ENABLE

/**********************************************************/
/**
 * @brief 
 * 开启 通用内存管理 的记录工作流程。
 * @note 
 * 返回的句柄，后续可按 xstd_mdebug_t 对象的操作接口获取其他信息。
 */
xstd_handle_t std_mdbcomm_start(void)
{
#if XSTD_MDBCOMM_ENABLE
    XASSERT(XSTD_NULL == xmdb_altor_comm);
    xmdb_altor_comm = std_mdebug_create();
    XASSERT(XSTD_NULL != xmdb_altor_comm);
    return (xstd_handle_t)xmdb_altor_comm;
#else // !XSTD_MDBCOMM_ENABLE
    return XSTD_NULL;
#endif // XSTD_MDBCOMM_ENABLE
}

/**********************************************************/
/**
 * @brief 关闭 通用内存管理 的记录工作流程。
 */
xstd_void_t std_mdbcomm_stop(void)
{
#if XSTD_MDBCOMM_ENABLE
    XASSERT(XSTD_NULL != xmdb_altor_comm);
    std_mdebug_destroy(xmdb_altor_comm);
    xmdb_altor_comm = XSTD_NULL;
#endif // XSTD_MDBCOMM_ENABLE
}

/**********************************************************/
/**
 * @brief 获取 通用内存管理 的记录工作句柄。
 * @note  后续可按 xstd_mdebug_t 对象的操作接口获取其他信息。
 */
xstd_handle_t std_mdbcomm_handle(void)
{
#if XSTD_MDBCOMM_ENABLE
    XASSERT(XSTD_NULL != xmdb_altor_comm);
    return (xstd_handle_t)xmdb_altor_comm;
#else // !XSTD_MDBCOMM_ENABLE
    return XSTD_NULL;
#endif // XSTD_MDBCOMM_ENABLE
}

/**********************************************************/
/**
 * @brief 获取当前 通用内存管理 中，所统计总共分配的内存大小。
 */
xstd_size_t std_mdbcomm_count(void)
{
#if XSTD_MDBCOMM_ENABLE
    return std_mdebug_count(xmdb_altor_comm);
#else // !XSTD_MDBCOMM_ENABLE
    return 0;
#endif // XSTD_MDBCOMM_ENABLE
}

////////////////////////////////////////////////////////////////////////////////

//====================================================================

// 
// 通用的内存管理 API
// 

/**********************************************************/
/**
 * @brief 默认的 执行内存块分配的回调函数。
 */
static xstd_mptr_t std_allocate(xstd_size_t xst_size)
{
#if XSTD_MDBCOMM_ENABLE
    xstd_mptr_t xmt_mptr = malloc(xst_size);
    if (XSTD_NULL != xmdb_altor_comm)
    {
        std_mdebug_record(xmdb_altor_comm, xmt_mptr, xst_size);
    }
    return xmt_mptr;
#else // !XSTD_MDBCOMM_ENABLE
    return malloc(xst_size);
#endif // XSTD_MDBCOMM_ENABLE
}

/**********************************************************/
/**
 * @brief 默认的 执行内存块释放的回调函数。
 */
static xstd_void_t std_dealloc(xstd_mptr_t xmt_mptr)
{
    if (XSTD_NULL != xmt_mptr)
    {
#if XSTD_MDBCOMM_ENABLE
        if (XSTD_NULL != xmdb_altor_comm)
        {
            std_mdebug_remove(xmdb_altor_comm, xmt_mptr);
        }
#endif // XSTD_MDBCOMM_ENABLE
        free(xmt_mptr);
    }
}

/**********************************************************/
/**
 * @brief 默认的 节点存储的元素对象 的 拷贝构造操作 的回调函数。
 * 
 * @param [out] xet_dptr : 目标存储的元素对象。
 * @param [in ] xet_sptr : 源数据的元素对象。
 * @param [in ] xet_ctxt : 节点元素的上下文信息。
 */
static xstd_void_t std_copyfrom(
                        xstd_elem_t xet_dptr,
                        xstd_elem_t xet_sptr,
                        xstd_ctxt_t xet_ctxt)
{
    memcpy(xet_dptr, xet_sptr, xet_ctxt->xstd_esize);
}

/**********************************************************/
/**
 * @brief 默认的 节点存储的元素对象 的 右值 move 拷贝构造操作 的回调函数。
 * 
 * @param [out] xet_dptr : 目标存储的元素对象。
 * @param [in ] xet_sptr : 源数据的元素对象。
 * @param [in ] xet_ctxt : 节点元素的上下文信息。
 */
static xstd_void_t std_copymove(
                        xstd_elem_t xet_dptr,
                        xstd_elem_t xet_sptr,
                        xstd_ctxt_t xet_ctxt)
{
    memcpy(xet_dptr, xet_sptr, xet_ctxt->xstd_esize);
}

/**********************************************************/
/**
 * @brief 默认的 节点存储的元素对象 的 析构操作 的回调函数。
 * 
 * @param [out] xet_dptr : 节点存储的元素对象。
 * @param [in ] xet_ctxt : 节点元素的上下文信息。
 */
static xstd_void_t std_destruct(
                        xstd_elem_t xet_dptr,
                        xstd_ctxt_t xet_ctxt)
{
#if XSTD_DEBUG_ENABLE
    memset(xet_dptr, 0, xet_ctxt->xstd_esize);
#endif // XSTD_DEBUG_ENABLE
}

/** 通用的内存管理对象 */
const xstd_allocator_t xstd_altor_comm =
{
    &std_allocate,
    &std_dealloc ,
    &std_copyfrom,
    &std_copymove,
    &std_destruct
};

////////////////////////////////////////////////////////////////////////////////

/**********************************************************/
/**
 * @brief 对两个 元素对象 进行 "==" 比较操作的回调函数类型。
 */
static xstd_bool_t std_comm_eq(
                        xstd_elem_t xet_lptr,
                        xstd_elem_t xet_rptr,
                        xstd_ctxt_t xet_ctxt)
{
    return (memcmp(xet_lptr, xet_rptr, xet_ctxt->xstd_esize) == 0);
}

/**********************************************************/
/**
 * @brief 对两个 元素对象 进行 "<" 比较操作的回调函数类型。
 */
static xstd_bool_t std_comm_lt(
                        xstd_elem_t xet_lptr,
                        xstd_elem_t xet_rptr,
                        xstd_ctxt_t xet_ctxt)
{
    return (memcmp(xet_lptr, xet_rptr, xet_ctxt->xstd_esize) < 0);
}

/**********************************************************/
/**
 * @brief 对两个 元素对象 进行 "<=" 比较操作的回调函数类型。
 */
static xstd_bool_t std_comm_le(
                        xstd_elem_t xet_lptr,
                        xstd_elem_t xet_rptr,
                        xstd_ctxt_t xet_ctxt)
{
    return (memcmp(xet_lptr, xet_rptr, xet_ctxt->xstd_esize) <= 0);
}

/**********************************************************/
/**
 * @brief 对两个 元素对象 进行 ">" 比较操作的回调函数类型。
 */
static xstd_bool_t std_comm_gt(
                        xstd_elem_t xet_lptr,
                        xstd_elem_t xet_rptr,
                        xstd_ctxt_t xet_ctxt)
{
    return (memcmp(xet_lptr, xet_rptr, xet_ctxt->xstd_esize) > 0);
}

/**********************************************************/
/**
 * @brief 对两个 元素对象 进行 ">=" 比较操作的回调函数类型。
 */
static xstd_bool_t std_comm_ge(
                        xstd_elem_t xet_lptr,
                        xstd_elem_t xet_rptr,
                        xstd_ctxt_t xet_ctxt)
{
    return (memcmp(xet_lptr, xet_rptr, xet_ctxt->xstd_esize) >= 0);
}

/** （使用内存模式的）通用类型的比较操作函数表 */
const xstd_compare_t xstd_fcmp_comm =
{
    &std_comm_eq,
    &std_comm_lt,
    &std_comm_le,
    &std_comm_gt,
    &std_comm_ge
};

//====================================================================

#define XSTD_COMM_ETYPE(etype, esize, ename, vtype)     \
                                                        \
static xstd_void_t std_copyfrom_##ename(                \
                        xstd_elem_t xet_dptr,           \
                        xstd_elem_t xet_sptr,           \
                        xstd_ctxt_t xet_ctxt)           \
{                                                       \
    *(vtype *)xet_dptr = *(vtype *)xet_sptr;            \
}                                                       \
                                                        \
static xstd_void_t std_copymove_##ename(                \
                        xstd_elem_t xet_dptr,           \
                        xstd_elem_t xet_sptr,           \
                        xstd_ctxt_t xet_ctxt)           \
{                                                       \
    *(vtype *)xet_dptr = *(vtype *)xet_sptr;            \
}                                                       \
                                                        \
static xstd_bool_t std_eq_##ename(                      \
                            xstd_elem_t xet_lptr,       \
                            xstd_elem_t xet_rptr,       \
                            xstd_ctxt_t xet_ctxt)       \
{                                                       \
    return (*(vtype *)xet_lptr == *(vtype *)xet_rptr);  \
}                                                       \
                                                        \
static xstd_bool_t std_lt_##ename(                      \
                            xstd_elem_t xet_lptr,       \
                            xstd_elem_t xet_rptr,       \
                            xstd_ctxt_t xet_ctxt)       \
{                                                       \
    return (*(vtype *)xet_lptr < *(vtype *)xet_rptr);   \
}                                                       \
                                                        \
static xstd_bool_t std_le_##ename(                      \
                            xstd_elem_t xet_lptr,       \
                            xstd_elem_t xet_rptr,       \
                            xstd_ctxt_t xet_ctxt)       \
{                                                       \
    return (*(vtype *)xet_lptr <= *(vtype *)xet_rptr);  \
}                                                       \
                                                        \
static xstd_bool_t std_gt_##ename(                      \
                            xstd_elem_t xet_lptr,       \
                            xstd_elem_t xet_rptr,       \
                            xstd_ctxt_t xet_ctxt)       \
{                                                       \
    return (*(vtype *)xet_lptr > *(vtype *)xet_rptr);   \
}                                                       \
                                                        \
static xstd_bool_t std_ge_##ename(                      \
                            xstd_elem_t xet_lptr,       \
                            xstd_elem_t xet_rptr,       \
                            xstd_ctxt_t xet_ctxt)       \
{                                                       \
    return (*(vtype *)xet_lptr >= *(vtype *)xet_rptr);  \
}                                                       \
                                                        \
const xstd_allocator_t xstd_altor_##ename =             \
{                                                       \
    &std_allocate,                                      \
    &std_dealloc ,                                      \
    &std_copyfrom_##ename,                              \
    &std_copymove_##ename,                              \
    &std_destruct                                       \
};                                                      \
                                                        \
const xstd_context_t xstd_ctxt_##ename =                \
{                                                       \
    etype,                                              \
    esize,                                              \
    XSTD_NULL,                                          \
    (xstd_altor_t)&xstd_altor_##ename                   \
};                                                      \
                                                        \
const xstd_compare_t xstd_fcmp_##ename =                \
{                                                       \
    &std_eq_##ename   ,                                 \
    &std_lt_##ename   ,                                 \
    &std_le_##ename   ,                                 \
    &std_gt_##ename   ,                                 \
    &std_ge_##ename                                     \
}

//====================================================================

XSTD_COMM_ETYPE(XSTD_ETYPE_CHAR   , sizeof(xstd_char_t   ), char   , xstd_char_t   );
XSTD_COMM_ETYPE(XSTD_ETYPE_UCHAR  , sizeof(xstd_uchar_t  ), uchar  , xstd_uchar_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_INT8   , sizeof(xstd_int8_t   ), int8   , xstd_int8_t   );
XSTD_COMM_ETYPE(XSTD_ETYPE_INT16  , sizeof(xstd_int16_t  ), int16  , xstd_int16_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_INT32  , sizeof(xstd_int32_t  ), int32  , xstd_int32_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_INT64  , sizeof(xstd_int64_t  ), int64  , xstd_int64_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_UINT8  , sizeof(xstd_uint8_t  ), uint8  , xstd_uint8_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_UINT16 , sizeof(xstd_uint16_t ), uint16 , xstd_uint16_t );
XSTD_COMM_ETYPE(XSTD_ETYPE_UINT32 , sizeof(xstd_uint32_t ), uint32 , xstd_uint32_t );
XSTD_COMM_ETYPE(XSTD_ETYPE_UINT64 , sizeof(xstd_uint64_t ), uint64 , xstd_uint64_t );
XSTD_COMM_ETYPE(XSTD_ETYPE_LONG   , sizeof(xstd_long_t   ), long   , xstd_long_t   );
XSTD_COMM_ETYPE(XSTD_ETYPE_LLONG  , sizeof(xstd_llong_t  ), llong  , xstd_llong_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_ULONG  , sizeof(xstd_ulong_t  ), ulong  , xstd_ulong_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_ULLONG , sizeof(xstd_ullong_t ), ullong , xstd_ullong_t );
XSTD_COMM_ETYPE(XSTD_ETYPE_FLOAT  , sizeof(xstd_float_t  ), float  , xstd_float_t  );
XSTD_COMM_ETYPE(XSTD_ETYPE_DOUBLE , sizeof(xstd_double_t ), double , xstd_double_t );
XSTD_COMM_ETYPE(XSTD_ETYPE_LDOUBLE, sizeof(xstd_ldouble_t), ldouble, xstd_ldouble_t);
XSTD_COMM_ETYPE(XSTD_ETYPE_HANDLE , sizeof(xstd_handle_t ), handle , xstd_handle_t );

////////////////////////////////////////////////////////////////////////////////

/**********************************************************/
/**
 * @brief 求 (2^N <= xst_value) 的 N 最大值。
 * @note  若 (0 == xst_value) 时，返回 XSTD_NAN_2PN 。
 */
xstd_size_t std_floor2pn(register xstd_size_t xst_value)
{
    register xstd_size_t xst_count = (0 == xst_value) ? XSTD_NAN_2PN : 0;
    while ((xst_count < (XSTD_NAN_2PN - 1)) &&
           ((((xstd_size_t)1) << (xst_count + 1)) <= xst_value))
    {
        ++xst_count;
    }
    return xst_count;
}

/**********************************************************/
/**
 * @brief 求 (2^N >= xst_value) 的 N 最小值。
 * @note  若 (xst_value > XSTD_MAX_2POW) 时，则返回 XSTD_NAN_2PN。
 */
xstd_size_t std_ceil2pn(register xstd_size_t xst_value)
{
    register xstd_size_t xst_count = (xst_value > XSTD_MAX_2POW) ? XSTD_NAN_2PN : 0;
    while ((xst_count < XSTD_NAN_2PN) &&
           ((((xstd_size_t)1) << xst_count) < xst_value))
    {
        ++xst_count;
    }
    return xst_count;
}

/**********************************************************/
/**
 * @brief 求 (2^N <= xst_value) 的 2^N 最大值。
 */
xstd_size_t std_floor2pow(register xstd_size_t xst_value)
{
    register xstd_size_t xst_check = 0;
    if (xst_value >= XSTD_MAX_2POW) 
        xst_value = XSTD_MAX_2POW;
    else
        for (xst_check  = xst_value & (xst_value - 1);
             xst_check != 0;
             xst_check &= (xst_check - 1))
        {
            xst_value = xst_check;
        }
    return xst_value;
}

/**********************************************************/
/**
 * @brief 求 (2^N >= xst_value) 的 2^N 最小值。
 * @note  若 (xst_value >= XSTD_MAX_2POW) 时，则返回 XSTD_MAX_2POW。
 */
xstd_size_t std_ceil2pow(register xstd_size_t xst_value)
{
    register xstd_size_t xst_check = 0;
    if (xst_value >= XSTD_MAX_2POW) 
        xst_value = XSTD_MAX_2POW;
    else
        for (xst_check  = xst_value & (xst_value - 1);
             xst_check != 0;
             xst_check &= (xst_check - 1))
        {
            xst_value = xst_check << 1;
        }
    return xst_value;
}

////////////////////////////////////////////////////////////////////////////////

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__

////////////////////////////////////////////////////////////////////////////////
